package com.cloudfun.campusshare.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.cloudfun.campusshare.common.constant.BidStatus;
import com.cloudfun.campusshare.common.constant.Code;
import com.cloudfun.campusshare.common.exception.BusinessException;
import com.cloudfun.campusshare.common.model.dto.BidCreateDTO;
import com.cloudfun.campusshare.common.model.dto.BidModifyDTO;
import com.cloudfun.campusshare.common.model.dto.BidQueryDTO;
import com.cloudfun.campusshare.common.model.vo.BidDetailVO;
import com.cloudfun.campusshare.common.model.vo.BidListVO;
import com.cloudfun.campusshare.common.response.PageResult;
import com.cloudfun.campusshare.entity.BidEntity;
import com.cloudfun.campusshare.repo.BidEntityRepo;
import com.cloudfun.campusshare.repo.SchoolEntityRepository;
import com.cloudfun.campusshare.service.BidService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.time.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * Created by Huqin on 2020/4/8
 */
@Service
public class BidServiceImpl implements BidService {

    @Autowired
    private BidEntityRepo bidEntityRepo;

    @Autowired
    private SchoolEntityRepository schoolEntityRepository;

    @Override
    public void create(BidCreateDTO createDTO) {
        this.checkBidTime(createDTO.getPublishTime(), createDTO.getStartTime(), createDTO.getEndTime());
        String schoolId = createDTO.getSchoolId();
        schoolEntityRepository.findById(schoolId).orElseThrow(() -> new BusinessException(Code.NODATA, "学校不存在"));
        BidEntity bidEntity = new BidEntity();
        BeanUtil.copyProperties(createDTO, bidEntity);
        bidEntity.setStatus(BidStatus.UNFINISHED);
        bidEntityRepo.save(bidEntity);
    }

    private void checkBidTime(Long pubTime, Long startTime, Long endTime) {
        Date pubDate = startOfDate(new Date(pubTime));
        Date startDate = startOfDate(new Date(startTime));
        Date endDate = startOfDate(new Date(endTime));
        Date today = startOfDate(new Date());
        LocalDateTime localDateTime = LocalDate.now().atStartOfDay();
        localDateTime.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli();
        // 发布日期<=开标日期<=当前时间<=结标日期
        if (startDate.before(pubDate) || today.before(startDate) || endDate.before(today)) {
            throw new BusinessException(Code.PARAMETER_ERROR, "发布、开标或者结标日期错误");
        }
    }

    private static Date startOfDate(Date date) {
        if (null == date) {
            return null;
        }
        LocalDate localDate = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    @Override
    public void update(BidModifyDTO modifyDTO) {
        BidStatus status = modifyDTO.getStatus();
        if (null != modifyDTO.getStatus()) {
            if (status.equals(BidStatus.COMPLETED)
                    && (StringUtils.isBlank(modifyDTO.getWinner()) || StringUtils.isBlank(modifyDTO.getPublicity()))) {
                throw new BusinessException(Code.PARAMETER_ERROR, "公示、中标方不能为空");
            }
            if (status.equals(BidStatus.UNFINISHED)) {
                this.checkBidTime(modifyDTO.getPublishTime(), modifyDTO.getStartTime(), modifyDTO.getEndTime());
            }
        }
        BidEntity bidEntity = bidEntityRepo.findById(modifyDTO.getId()).orElseThrow(() -> new BusinessException(Code.NODATA, "学校不存在"));
        CopyOptions copyOptions = CopyOptions.create();
        copyOptions.setIgnoreNullValue(true);
        BeanUtil.copyProperties(modifyDTO, bidEntity, copyOptions);
        if (bidEntity.getStatus().equals(BidStatus.UNFINISHED)) {
            bidEntity.setPublicity(null);
            bidEntity.setWinner(null);
        }
        bidEntityRepo.save(bidEntity);
    }

    @Override
    public void delete(String id) {
        BidEntity bidEntity = bidEntityRepo.findById(id).orElseThrow(() -> new BusinessException(Code.NODATA, "学校不存在"));
        bidEntityRepo.delete(bidEntity);
    }

    @Override
    public BidDetailVO detail(String id) {
        BidEntity bidEntity = bidEntityRepo.findById(id).orElseThrow(() -> new BusinessException(Code.NODATA, "招标不存在"));
        BidDetailVO bidDetailVO = new BidDetailVO();
        BeanUtil.copyProperties(bidEntity, bidDetailVO);
        String schoolName = bidEntity.getSchool().getName();
        bidDetailVO.setSchoolName(schoolName);
        return bidDetailVO;
    }

    @Override
    public PageResult<BidListVO> search(BidQueryDTO queryDTO, Pageable pageable) {
        Specification<BidEntity> specification = (root, query, builder) -> {
            List<Predicate> predicateList = new ArrayList<>();

            if (null != queryDTO.getStatus()) {
                predicateList.add(builder.equal(root.get("status"), queryDTO.getStatus()));
            }
            if (StringUtils.isNotBlank(queryDTO.getKeyword())) {
                predicateList.add(builder.like(root.get("name"), "%" + queryDTO.getKeyword() + "%"));
            }
            if (StringUtils.isNotBlank(queryDTO.getPubTimeBegin())) {
                predicateList.add(builder.greaterThanOrEqualTo(root.get("publishTime"), queryDTO.getPubTimeBegin()));
            }
            if (StringUtils.isNotBlank(queryDTO.getPubTimeEnd())) {
                predicateList.add(builder.lessThanOrEqualTo(root.get("publishTime"), queryDTO.getPubTimeEnd()));
            }
            if (StringUtils.isNotBlank(queryDTO.getStartTimeBegin())) {
                predicateList.add(builder.greaterThanOrEqualTo(root.get("startTime"), queryDTO.getStartTimeBegin()));
            }
            if (StringUtils.isNotBlank(queryDTO.getStartTimeEnd())) {
                predicateList.add(builder.lessThanOrEqualTo(root.get("startTime"), queryDTO.getStartTimeEnd()));
            }
            if (StringUtils.isNotBlank(queryDTO.getEndTimeBegin())) {
                predicateList.add(builder.greaterThanOrEqualTo(root.get("endTime"), queryDTO.getEndTimeBegin()));
            }
            if (StringUtils.isNotBlank(queryDTO.getEndTimeEnd())) {
                predicateList.add(builder.lessThanOrEqualTo(root.get("endTime"), queryDTO.getEndTimeEnd()));
            }

            Predicate[] predicates = new Predicate[predicateList.size()];
            predicateList.toArray(predicates);
            return builder.and(predicates);
        };

        Page<BidEntity> entityPage = bidEntityRepo.findAll(specification, pageable);
        long totalElements = entityPage.getTotalElements();
        List<BidListVO> content = entityPage.getContent()
                .stream()
                .map(entity -> {
                    BidListVO listVO = new BidListVO();
                    BeanUtil.copyProperties(entity, listVO);
                    String schoolName = entity.getSchool().getName();
                    listVO.setSchoolName(schoolName);
                    return listVO;
                }).collect(Collectors.toList());

        PageResult<BidListVO> result = new PageResult<>();
        result.setElements(content);
        result.setTotalSize(totalElements);
        return result;
    }
}
